package com.ubigate.CooknaviHA;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Window;
import android.webkit.CookieSyncManager;
import android.webkit.DownloadListener;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class WebviewActivity extends Activity implements DownloadListener {
	private static final String TAG = "WebviewActivity";
	private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile("attachment\\s*;\\s*filename\\s*=\\s*\"*([^\"]*)\"*");
	//	글자 검색을위한 패턴선언
	private WebView mWebView;	//	웹뷰 변수선언
	private WebSettings mSetting = null;	// 웹환경설정 변수선언
	Activity activity = null;	//	액티비티 변수선언

	ProgressDialog mLoading;	//	로딩을위한 프로그레스다이얼로그 선언
	RecipeDownThread mThread;	//	다운을받는 작업스레드 선언
	
	private final Handler handler = new Handler();	//	핸들러객체 선언

	boolean bDownloadSuccess = false;	//	다운로드 성공/실패 변수
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_PROGRESS);
        //	윈도우창에 막대 모양 프로그레스 창을 생성한다.
        setContentView(R.layout.webview);
        // webview.xml 페이지를 가져옴
        activity = this;
        // 액티비티변수에 현재 액티비티를 넣어줌
        CookieSyncManager.createInstance(activity);
        //	현재 액티비티로 쿠키를 생성해줌(초기화)
        CookieSyncManager.getInstance().startSync();
        //	쿠키 시작
        mWebView = (WebView) findViewById(R.id.webview);
        //	웹뷰변수에다가 webview id를 통해 연결시켜줌.
        
        // HTML5를 위한 WebSettings 설정
        /*
         * 앱과웹 연동을 위한 웹 세팅 설정
         */
        mSetting = mWebView.getSettings();
        // 	mSetting에 mWebView의 세팅옵션설정 변수를 대입함.
        mSetting.setJavaScriptEnabled(true);
        //	자바스크립트 사용 설정
        mSetting.setJavaScriptCanOpenWindowsAutomatically(true);
        //	오픈윈도우를 자동적으로 사용하도록 설정
        mSetting.setLoadsImagesAutomatically(true);
        //	이미지를 자동적으로 불러오게 설정
//      mSetting.setGeolocationEnabled(true);
//      mSetting.setPluginsEnabled(true);
//      mSetting.setSupportZoom(true);
//      mSetting.setBuiltInZoomControls(true);
        // HTML5 Database
        mSetting.setDatabaseEnabled(true);
        //	데이타베이스 사용 설정
        mSetting.setDatabasePath("/data/data/com.ubigate.CooknaviHA/database");
        //	데이타베이스 경로 설정
        // HTML5 DOM Storage
        mSetting.setDomStorageEnabled(true);
        // 	html5 의 localStoage을 사용할 수 있게 함
        // HTML5 Cache
        mSetting.setAppCacheMaxSize(1024 * 1024 * 8);
        //	디폴트캐시사이즈를 8MB로 설정
        mSetting.setAppCachePath("/data/data/com.ubigate.CooknaviHA/cache");
        //	캐시경로 설정
        mSetting.setAppCacheEnabled(true);
        //	캐시 사용 설정
        mSetting.setAllowFileAccess(true);
        //	파일 접근 설정
        mSetting.setCacheMode(WebSettings.LOAD_DEFAULT);
        //	캐시 모드 설정
        mWebView.addJavascriptInterface(new CooknaviHABridge(), "CooknaviHA");
        //	클라이언트에서 사용할 이름 설정
		String sUrl = getIntent().getStringExtra("url");
		//	화면에서 url 경로를 가져온다.
        if (sUrl == null) sUrl = "http://www.cooknavi.co.kr";
        //	만약 sUrl이 비어있으면 쿡나비 url을 넣어줌.
        mWebView.loadUrl(sUrl);
        //	url을 sUrl주소에 따라 뿌려줌
        mWebView.setWebViewClient(new CooknaviWebViewClient());
        //	웹클라이언트 지정
        mWebView.setWebChromeClient(new CooknaviWebChromeClient());
        //	웹뷰클라이언트 : 크롬
        mWebView.setDownloadListener(this);
        //	다운로드 이벤트의 콜백 등록
        mLoading = ProgressDialog.show(WebviewActivity.this, "", "데이터를 가져오고 있습니다..", true);
        //	mLoading 프로그래스다이얼로그에 메세지를 띄워줌 
    }

    /*
     * 자바스크립트에서 안드로이드 호출클래스
     */
    private class CooknaviHABridge {
    	@SuppressWarnings("unused")
		public void setMessage(final String arg) {
    		handler.post(new Runnable () {	
    			//	핸들러는 스레드간의 메시지 전달.스레드에서 메인으로 전송해야 하므로. handler사용
    			 
    			public void run() {
    				Log.d("WebviewActivity", "arg : "+arg);
    				//	디버깅 로그 메시지를 보냄
    			}
    		});
    	}
    }
    
    // 버튼 클릭시 발생하는 함수
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    	//	버튼이 눌러지고 뒤로갈수있는 상태시 실행.
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        //	안되면 상위클래스의 함수 실행
        return super.onKeyDown(keyCode, event);
    }
    
    /*
     * 웹 페이지 이동 클래스
     */
    private class CooknaviWebViewClient extends WebViewClient {
    	//	페이지 이동시 불리워지는 함수
    	@Override
    	public boolean shouldOverrideUrlLoading(WebView view, String url) {
    		Log.d(TAG, "shouldOverrideUrlLoading (url:"+url+")");
    		// 	디버깅 메시지 전달
    		if (url.startsWith("tel:")) {	//	url이 tel:로 시작하면
    			Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
    			startActivity(callIntent);	//	인텐트를 연결하여 url로 전화를검.
    		} else if (url.startsWith("http:")||url.startsWith("https:")){
        		view.loadUrl(url);    		
        		//	url이 http: or https: 로 시작하면 바로 url주소를 load함
    		} else {
    			Intent appIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    			startActivity(appIntent);
    			//	인텐트를 연결하여 url을 보여줌
     		}
    		return true;
    	}
    	//	페이지 이동시 에러
    	public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    		Log.d(TAG, "CooknaviWebView-onReceivedError");
    		//	디버깅 메시지 전달
    		Toast.makeText(activity, "연결 실패 : "+ description , Toast.LENGTH_SHORT).show();
    		//	연결실패라고 토스트박스를 띄워줌
    	}
    	//	페이지 완료시
    	public void onPageFinished(WebView view, String url) {
    		mLoading.cancel();	//	로딩을 취소함
    		mLoading.dismiss();	//	닫기
    	}
    }
    
    /*
     * 프로그레스 창 설정 클래스
     */
    private class CooknaviWebChromeClient extends WebChromeClient {
    	//	프로그레스창이 채워지는 함수(바 조절)
    	public void onProgressChanged(WebView view, int progress) {
    		Log.d(TAG, "onProgressChanged : "+ progress);
    		//	디버깅 메시지 전송
    		activity.setProgress(progress * 100);
    		//	프로그래스창이 progress * 100을 보여줌(바 위치를 정함)
    	}
    	//	알림
    	public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    		Toast.makeText(activity, message, 3000).show();
    		//	메시지를 3000 시간동안 토스트박스형태로 보여줌.
    		result.confirm();
    		//	결과를 처리됨
    		return true;
    	}
    }

    /*
     * 브라우저를 통해 다운받을시
     * 이 함수가 불리우게 됨
     * (non-Javadoc)
     * @see android.webkit.DownloadListener#onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long)
     */
	@Override
	public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onDownloadStart-");
		//	디버깅 메시지 전송
		try {
			String tContentDisposition = URLDecoder.decode(contentDisposition,"UTF-8");
			String tFilename = parseContentDisposition(tContentDisposition);
			String tExtension = tFilename.substring(tFilename.length()-3); 
			//	URL, 파일이름 등의 스트링 입력
			Log.d(TAG, "contentDisposition : "+ tContentDisposition+", filename : "+ tFilename);
			//	디버깅 메시지 전송
			if (tExtension.equals("rcs")) {
				// Recipe File
				Log.d(TAG, "Recipe file");
				Log.d(TAG, "url : "+url+", UA : "+userAgent);
				Log.d(TAG, "mimetype : "+mimetype+", contentLength : "+contentLength);
				// 	디버깅 메시지 전송
				mLoading.show();
				//	로딩 프로그레스를 보여줌
				mThread = new RecipeDownThread(url, tFilename);
				//	쓰레드 자원 할당
				mThread.start();
				//	쓰레드 스타트
			} else {
				// Non Recipe File
				Log.d(TAG, "Non-recipe file");
				Log.d(TAG, "url : "+url+", UA : "+userAgent);
				Log.d(TAG, "mimetype : "+mimetype+", contentLength : "+contentLength);
				//	디버깅 메시지 전송
				Intent intent = new Intent(Intent.ACTION_VIEW ,Uri.parse(url));
				startActivity(intent);
				//	인텐트를 통해 url을 보여줌
			}
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();	//	에러
		}
	}
	/*
	 * 	Content-Disposition 헤더에 여러 param 이 있겠지만 
	 * 	일단 첨부파일 및 음악파일 download 시에 filename 이 들어 있다.
	 * 	소스 상에서 이 Content-Disposition 을 가지고 저장할 filename 을 가져 온다.
	 */
    static String parseContentDisposition(String contentDisposition) {
        try {
            Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
            if (m.find()) {
                return m.group(1);
            }
        } catch (IllegalStateException ex) {
             // This function is defined as returning null when it can't parse the header
        }
        return null;
    }
	
    //다운로드를 받는 작업 스레드
    class RecipeDownThread extends Thread {
    	String mAddr;		// 데이터를 가져올 서비스 URL 주소
    	String mFilename;	// 저장될 레시피 파일명
    	
    	RecipeDownThread(String addr, String filename) {	// 생성자
    		mAddr = addr;
    		mFilename = filename;
    	}
    	
    	public void run() {
    		DownloadRecipe(mAddr, mFilename);
    		//	다운로드를 받음
    		//	핸들러 호출
    		mAfterDown.sendEmptyMessage(0);
    	}
    }
    
    void DownloadRecipe(String mAddr, String mFilename) {
		Log.d(TAG, "RecipeDownThread-DownloadRecipe");
		//	디버깅 메시지 전송

		try {
			InputStream is;
		    URL url = new URL(mAddr);
		    //	url 객체를 mAddr로 생성
		    HttpURLConnection con = (HttpURLConnection) url.openConnection();
		    //	HttpURLConnection 객체 생성
		    con.setRequestMethod("GET");
		    //	HTTP전송방식을 get으로 설정
		    con.setDoOutput(true);
		    //	위의연결된 페이지에 파라미터 전달
		    con.connect();
		    //	connect연결
		    is = con.getInputStream();
		    //	연결된 페이지에서 InputStream 을 받아옴
			// Path and File where to download the APK
		    File dir = ((CooknaviApp)getApplicationContext()).extDir;
		    //	CooknaviApp 디렉토리 경로의 콘텍스트를 가져와 dir에 대입
			dir.mkdirs(); // creates the download directory if not exist
			File outputFile = new File(dir, mFilename);
			//	파일객체를 생성해서 mFilename을 dir의 경로에 대입.
			FileOutputStream fos = new FileOutputStream(outputFile);
			//	파일객체를 스트림형태로 받아서 스트림객체에 대입.
			// Save file from URL to download directory on external storage
			byte[] buffer = new byte[1024];	// 바이트형 배열 1024개 선언, 1kb씩 읽겠다.
			int len = 0;
			//	1kb씩 읽어서 write함
			while ((len = is.read(buffer)) != -1) {
			    fos.write(buffer, 0, len);
			}
			fos.flush();	//	내부버퍼에 남아있는 데이터를 강제로 파일로 전송.
			fos.close();	//	파일 닫기
			is.close();		//	inputstream 닫기

			// finally, install the downloaded file
			bDownloadSuccess = true;
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    Handler mAfterDown = new Handler() {	// 	핸들러 객체 선언 및 생성
    	public void handleMessage(Message msg) { 
    		Log.d(TAG, "RecipeDownThread-mAfterDown");
    		//프로그래스 대화상자를 종료합니다.
    		mLoading.dismiss();
    		if (bDownloadSuccess) {	//	다운로드가 성공 했을경우
    			Toast.makeText(WebviewActivity.this, "레시피 파일 다운로드가 완료 되었습니다.", 1500).show();
    			//	토스트박스를 통해 위 메시지를 일정시간동안 보여줌
    		} else {	//	다운로드가 실패 했을경우
    			Toast.makeText(WebviewActivity.this, "레시피 파일을 다운로드 할 수 없습니다. 잠시후 다시 이용해 주세요.", 1500).show();
    			//	토스트박스를 통해 위 메시지를 일정시간동안 보여줌
    		}
    		bDownloadSuccess = false;
    		//	다운로드 성공시 true로 바뀌므로 항상 작업후에 false로 초기화 해주어야 함.
    	}
    };	
	
}
